﻿using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
using Microsoft.SharePoint.Administration;
using ServBus.ListForm2013.Utility;

namespace ServBus.ListForm2013.License
{
    internal class LicenseContainer
    {
        private static readonly byte[] _verifyKey = { 0x6, 0x2, 0x0, 0x0, 0x0, 0xA4, 0x0, 0x0, 0x52, 0x53, 0x41, 0x31, 0x0, 0x4, 0x0, 0x0, 0x1, 0x0, 0x1, 0x0, 0x89, 0x18, 0x57, 0x58, 0xE2, 0xBB, 0x3F, 0x11, 0x81, 0x66, 0xB9, 0x31, 0x77, 0x9E, 0x3D, 0x27, 0x8C, 0xE, 0xF4, 0x6D, 0x2C, 0xC6, 0xCC, 0x7E, 0x6B, 0x68, 0x12, 0x82, 0xE9, 0xF, 0xA4, 0x44, 0x27, 0x5B, 0x94, 0x9, 0x36, 0x9D, 0xC4, 0xE6, 0xBD, 0x3C, 0x56, 0xA9, 0x7C, 0x83, 0x32, 0xBE, 0x88, 0x1C, 0x94, 0x9E, 0xE3, 0x85, 0x1E, 0xE8, 0x56, 0xC5, 0xE7, 0x63, 0x23, 0x40, 0x5, 0x1A, 0xB, 0x17, 0xFD, 0xA2, 0xED, 0x76, 0x1F, 0x7E, 0x49, 0xF7, 0xCB, 0xFB, 0x2B, 0xEB, 0xAC, 0x61, 0x48, 0x15, 0x48, 0xED, 0x76, 0xC9, 0x73, 0xCD, 0x38, 0x29, 0x96, 0x79, 0x0, 0x2C, 0xD4, 0xFA, 0xEA, 0xE1, 0x37, 0x90, 0xA4, 0xFE, 0xE1, 0xBF, 0xA2, 0x5D, 0x17, 0x1D, 0x6D, 0xAA, 0xC1, 0x3B, 0x8D, 0xE0, 0x9E, 0xC1, 0x21, 0xC8, 0x39, 0x5C, 0xEE, 0xA2, 0xC6, 0xAF, 0x6F, 0xC3, 0xD, 0xC5 };

        private LicenseContainer()
        { 
        }

        private static object _syncLock = new object();
        private static bool _isValid;
        private static License _license;

        public static License ProductLicense 
        {
            get 
            {
                EnsureLicense(false);
                return _license; 
            }
        }

        public static bool IsLicenseEmpty
        {
            get
            {
                //ErrorLog.Write("IsLicenseEmpty:in", System.Diagnostics.EventLogEntryType.Warning);
                EnsureLicense(false);                
                return _license == null;
            }
        }

        public static bool IsLicenseExpire
        {
            get
            {
                EnsureLicense(false);
                if (_license == null)
                    return false;
                return _license.ExpirationDate < DateTime.Now;
            }
        }

        public static bool IsLicenseValid
        {
            get
            {
                EnsureLicense(false);
                return _isValid;
            }
        }

        private static void EnsureLicense(bool force)
        {
            
            if (_license != null && !force)
            {
                //ErrorLog.Write("IsLicenseEmpty:out Directly", System.Diagnostics.EventLogEntryType.Warning);
                return;
            }
            lock (_syncLock)
            {
                try
                {
                    _isValid = false;
                    _license = null;
                    string licenseKey = Convert.ToString(SPFarm.Local.Properties[Constants.FARM_LICENSE_KEY]);

                    if (!string.IsNullOrEmpty(licenseKey))
                    {
                        //ErrorLog.Write("licenseKey is not null or empty:"+licenseKey, System.Diagnostics.EventLogEntryType.Warning);
                        byte[] bufferOrig = Convert.FromBase64String(licenseKey);
                        byte[] buffer = CryptoUtility.DecryptDES(bufferOrig);
                        byte[] licenseInfo = new byte[buffer.Length - 128];
                        byte[] verifyInfo = new byte[128];
                        Array.Copy(buffer, 0, licenseInfo, 0, licenseInfo.Length);
                        Array.Copy(buffer, licenseInfo.Length, verifyInfo, 0, 128);

                       // ErrorLog.Write("Deserialize licenseKey begin:"+licenseInfo.Length+","+licenseInfo.ToString(), System.Diagnostics.EventLogEntryType.Warning);
                        // Deserialize License
                        using (MemoryStream stream = new MemoryStream(licenseInfo))
                        {
                            IFormatter formatter = new BinaryFormatter();
                            _license = formatter.Deserialize(stream) as License;

                            //bool _licenseFlag = false;
                            //if (_license == null) _licenseFlag = true;
                            //ErrorLog.Write("IsLicenseEmpty:[_license=null?]" + _licenseFlag, System.Diagnostics.EventLogEntryType.Warning);
                            //ErrorLog.Write("_licenseExpirateDate = " + _license.ToString(), System.Diagnostics.EventLogEntryType.Warning);
                        }
                        
                        // Verify License
                        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                        rsa.ImportCspBlob(_verifyKey);
                        _isValid = rsa.VerifyData(licenseInfo, new SHA1CryptoServiceProvider(), verifyInfo);
                        //fake license
                        //_isValid = true;

                        //ErrorLog.Write("licenseUploadOk:"+_isValid, System.Diagnostics.EventLogEntryType.Information);
                    }
                }
                catch(Exception ex)
                {
                    ErrorLog.Write("Invalid License" + "\r\n" + ex.Message + "\r\n" + ex.StackTrace, System.Diagnostics.EventLogEntryType.Error);
                }
            }
        }

        public static void UpdateLicense()
        {
            EnsureLicense(true);
        }
    }
}
